//
//  File.swift
//  
//
//  Created by 钟志远 on 2021/3/26.
//

import Foundation
import Vapor

struct MyErrorMiddleware: Middleware {
    func respond(to request: Request, chainingTo next: Responder) -> EventLoopFuture<Response> {
        return next.respond(to: request).flatMapErrorThrowing { (err) -> Response in
            deal(req: request, error: err)
        }
    }
    
    func deal(req: Request, error: Error) -> Response {

        // variables to determine
        let status: HTTPResponseStatus
        let reason: String
        let headers: HTTPHeaders

        // inspect the error type
        switch error {
        case let abort as AbortError:
            // this is an abort error, we should use its status, reason, and headers
            reason = abort.reason
            status = abort.status
            headers = abort.headers
        default:
            // if not release mode, and error is debuggable, provide debug info
            // otherwise, deliver a generic 500 to avoid exposing any sensitive error info
            let environment = req.application.environment
            reason = environment.isRelease
                ? "Something went wrong."
                : String(describing: error)
            status = .internalServerError
            headers = [:]
        }
        
        // Report the error to logger.
        req.logger.report(error: error)
        
        // create a Response with appropriate status
        let response = Response(status: status, headers: headers)
        
        // attempt to serialize the error to json
        do {
            let errorResponse = CustomResponseData<[String: String]>.fail(code: Int(status.code), message: reason, data: [:])
            response.body = try .init(data: JSONEncoder().encode(errorResponse))
            response.headers.replaceOrAdd(name: .contentType, value: "application/json; charset=utf-8")
        } catch {
            response.body = .init(string: "Oops: \(error)")
            response.headers.replaceOrAdd(name: .contentType, value: "text/plain; charset=utf-8")
        }
        return response
    }
}
